package org.elip.teststatistics.server;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.VFS;
import org.elip.teststatistics.client.LogsService;
import org.elip.teststatistics.server.selectors.LogsFileSelector;
import org.elip.teststatistics.server.selectors.ScreenshotsFileSelector;
import org.elip.teststatistics.server.selectors.SuiteFolderSelector;
import org.elip.teststatistics.shared.Log;
import org.elip.teststatistics.shared.Logs;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
public class LogsServiceImpl extends RemoteServiceServlet implements LogsService {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static String pathToTgrid;
	private static String pathToBuilds;

	@Override
	public void init() throws ServletException {

		if (File.pathSeparator == "/") {
			pathToTgrid = "/export/tgrid";
		}
		else {
			pathToTgrid = "smb://GSPACES\\ca:password@192.168.10.13/tgrid";
		}
		super.init();
	}
	
	public Logs generateLogs(String testName, String group,String product, Date fromDate, Date toDate) throws IllegalArgumentException {
		
		if (product.equals("XAP")) {
			pathToBuilds = pathToTgrid + "/sgtest-xap/deploy/local-builds";
		}
		else {
			pathToBuilds = pathToTgrid + "/sgtest-cloudify/deploy/local-builds";
		}
		List<Log> result = new ArrayList<Log>();
		try {
			FileSystemManager manager = VFS.getManager();
			FileObject buildsDir = manager.resolveFile(pathToBuilds);
			FileObject[] builds = buildsDir.getChildren();
			for (FileObject build : builds) {

				Date buildDate = new Date(build.getContent().getLastModifiedTime());

				boolean greaterThanEquals = false;
				boolean lessThanEquals = false;

				greaterThanEquals = (buildDate.compareTo(fromDate) >= 0);
				lessThanEquals = (buildDate.compareTo(toDate) <= 0);

				if ( (greaterThanEquals && lessThanEquals)) {
					String buildNumber = build.getName().getBaseName();
					String pathToTests = pathToBuilds + "/" + buildNumber;
					FileObject testsDir = manager.resolveFile(pathToTests);
					if (testsDir.exists()) {
						FileObject[] testDirs = scanDirectoryForTestRelatedDir(testsDir, testName, group);
						FileObject[] logFiles = scanDirectoriesForLogs(testDirs);
						FileObject[] screenshots = null;
						if (group.contains("webui")) {
							screenshots = scanDirectoriesForScreenShots(testDirs);
						}
						if (logFiles != null) {

							Log testLog = new Log();
							testLog.setProduct(product);
							testLog.setBuildNumber(buildNumber);
							testLog.setGroup(group);
							testLog.setDate(buildDate);

							String testLogString = "";
							for (int i = 0 ; i < logFiles.length ; i++) {
								testLogString  += "<br>" + readStreamToString(logFiles[i].getContent().getInputStream());
							}
							if (testLogString.contains("Test Passed")) {
								testLog.setFailed(false);
								testLog.setPassed(true);
							}
							if (testLogString.contains("Test Failed")) {
								testLog.setPassed(false);
								testLog.setFailed(true);
							}
							if (testLogString.contains("Test Configuration Failed")) {
								testLog.setSkipped(true);
							}

							String[] links = new String[0];
							if (screenshots != null) {
								links = new String[screenshots.length];
								for (int i = 0 ; i < links.length ; i++) {
									String screenshotUrl = screenshots[i].getURL().toString();
									links[i] = screenshotUrl.replace(pathToTgrid, "http://192.168.9.121:8087")
										.replace("/deploy/local-builds", "");
								}
							}

							testLog.setLog(testLogString);
							testLog.setLinksToScreenshots(links);
							result.add(testLog);
						}
					}
				}
			}

		}
		catch (FileSystemException e) {
			e.printStackTrace();

		} catch (IOException e) {
			e.printStackTrace();
		}
		Log[] array = new Log[result.size()];

		Log[] array2 = result.toArray(array);

		Arrays.sort(array2, new LogsComparator());

		Logs logs = new Logs(array2, testName);

		return logs;
	}

	private String readStreamToString(InputStream inputStream) throws IOException {

		InputStreamReader in = new InputStreamReader(inputStream);
		BufferedReader reader = new BufferedReader(in);
		String inputLine = reader.readLine();
		String result = "";
		if (inputLine != null) {
			result = inputLine;
			while ((inputLine = reader.readLine()) != null) {
				if (inputLine.contains("Test Passed")) {
					result = result + "<br>" + "<span style=" + '"' + "background-color:#00cc66;font-weight:bold" + '"' + ">" + 
					inputLine + "</span>";
				}
				else { 
					if (inputLine.contains("Test Failed")) {
						result = result + "<br>" + "<span style=" + '"' + "background-color:#ff6666;font-weight:bold" + '"' + ">" + 
						inputLine + "</span>";
					}
					else {
						if (inputLine.contains("Test Configuration Failed")) {
							result = result + "<br>" + "<span style=" + '"' + "background-color:#ffff00;font-weight:bold" + '"' + ">" + 
							inputLine + "</span>";
						}
						else result = result + "<br>" + inputLine;
					}
				}
			}
		}
		in.close();
		reader.close();
		return result;
	}

	private FileObject[] scanDirectoriesForScreenShots(FileObject[] build) throws FileSystemException {

		List<FileObject> res = new ArrayList<FileObject>();
		try {
			for (FileObject f : build) {
				FileObject[] tmp = f.findFiles(new ScreenshotsFileSelector());
				for (FileObject file : tmp) {
					res.add(file);
				}
			}
			FileObject[] testsLogs = new FileObject[res.size()]; 
			return res.toArray(testsLogs);
		}
		catch (FileSystemException e) {
			System.err.println(e);
		}
		return null;

	}

	private FileObject[] scanDirectoriesForLogs(FileObject[] build) throws FileSystemException {

		if (build.length == 0) {
			return null;
		}
		List<FileObject> res = new ArrayList<FileObject>();
		try {
			
			for (FileObject f : build) {
				FileObject[] tmp = f.findFiles(new LogsFileSelector());
				if (tmp.length > 0) {
					res.addAll(Arrays.asList(tmp));
				}
			}
			if (res.size() != 0) {
				FileObject[] testsLogs = new FileObject[res.size()]; 
				return res.toArray(testsLogs);
			}
		}
		catch (FileSystemException e) {
			System.err.println(e);
		}
		return null;
	}

	class LogsComparator implements Comparator<Log> {

		@Override
		public int compare(Log o1, Log o2) {
			String buildNumber1 = o1.getBuildNumber();
			String buildNumber2 = o2.getBuildNumber();	
			String[] parts1 = buildNumber1.split("_")[1].split("-");
			String[] parts2 = buildNumber2.split("_")[1].split("-");	
			int buildVersion1 = Integer.parseInt(parts1[0]);
			int buildVersion2 = Integer.parseInt(parts2[0]);
			int buildMilestone1 = Integer.parseInt(parts1[1]);
			int buildMilestone2 = Integer.parseInt(parts2[1]);
			if (buildVersion1 > buildVersion2) return 1;
			else {
				if (buildVersion1 < buildVersion2) return -1;
				if (buildVersion1 == buildVersion2) {
					if (buildMilestone1 > buildMilestone2) return 1;
					else {
						if (buildMilestone1 < buildMilestone2) return -1;
					}
				}
			}
			return 0;	
		}
	}


	private FileObject[] scanDirectoryForTestRelatedDir(FileObject build, String testName, String suiteName) {

		List<FileObject> res = new ArrayList<FileObject>();
		try {
			if (build.getName().getBaseName().contains("build_")) {
				if (build.findFiles(new SuiteFolderSelector(FileType.FOLDER, suiteName)).length != 0) {
					FileObject[] buildChildren = build.getChildren();
					for (FileObject f : buildChildren) {
						if (f.getName().getPath().contains(testName)) res.add(f);
					}
				}
			}

			FileObject[] result = new FileObject[res.size()];
			return res.toArray(result);
		}
		catch (FileSystemException e) {
			e.printStackTrace();
		}
		return null;
	}
}